package com.gzm.check;

import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gzm.check.utils.ConvEnum;
import com.gzm.health.util.BasicConstant;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @program: dataconvert
 * @description: 抽象类
 * @author: zxw_
 * @create: 2020-12-28 10:19
 */
public abstract class CheckC<T extends IService<M>,M,F extends IService<C>,C> {


    // 分页开始,第一页
    private static final AtomicLong ATOMICLONG = new AtomicLong(1);

    // 每页条数,默认一次处理一万条数据
    private static final int IMIT = 10000;

    // 最大线程数
    private static final int MAXTHREAD = 10;

    // 线程池
    private static final ExecutorService pool = Executors.newFixedThreadPool(MAXTHREAD);

    // 可循环栅格
    private static final Semaphore SEMAPHORE = new Semaphore(MAXTHREAD);

    private IService tService;

    private IService fService;

    protected void setIService(T tService,F fService) {
        this.tService = tService;
        this.fService = fService;
    }

    public void run(String orderCol) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
        queryWrapper.orderByAsc(orderCol);

        LocalDateTime start = LocalDateTime.now(); // 开始时间

        while (true) {
            long andIncrement = ATOMICLONG.getAndIncrement();
            Page<M> page = (Page<M>) tService.page(new Page<M>(andIncrement, IMIT), queryWrapper);

            List<M> records = page.getRecords();
            if (IterUtil.isEmpty(records) || IMIT > records.size()) {
                // 最后一次的数据了
                setRecode(records, 0, records.size());
                break;// 处理完直接跳出
            }
            for (int i = 0; i < MAXTHREAD; i++) {
                int pages = i;
                pool.execute(() -> { // 多线程执行
                    setRecode(records, pages * (IMIT / MAXTHREAD), (pages + 1) * (IMIT / MAXTHREAD));
                });
            }
            try {
                Thread.sleep(1000); // 主线程睡眠一秒防止下面抢到凭证
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                SEMAPHORE.acquire(MAXTHREAD); // 一次获取最大凭证数保证所有线程都执行完毕
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            SEMAPHORE.release(MAXTHREAD);// 重置型号量
            String fromat = StrUtil.format("====> 执行完了第{} 次", andIncrement);
            System.out.println(fromat);

        }

        LocalDateTime end = LocalDateTime.now();// 结束时间
        Duration between = LocalDateTimeUtil.between(start, end);


        String sta = LocalDateTimeUtil.format(start, DatePattern.NORM_DATETIME_PATTERN);
        String en = LocalDateTimeUtil.format(end, DatePattern.NORM_DATETIME_PATTERN);

        String format = StrUtil.format("开始时间 : {} ,结束时间 : {} ,执行时间 :{}分钟", sta, en, between.toMinutes());
        System.out.println(format);
        pool.shutdown();// 销毁线程池

    }

    public void setRecode(List<M> list, int begin, int end) {
        try {
            SEMAPHORE.acquire();// 获取凭证
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        List<C> lists = new ArrayList<>(1000);
        for (int i = begin; i < end; i++) {
            baseHealthToRecode(list.get(i), lists);
        }
        fService.saveBatch(lists);
        SEMAPHORE.release();// 线程执行完释放凭证
    }

    protected abstract void baseHealthToRecode(M record, List<C> newList);


    /**
     * 获取分隔符后的文本  不包含分隔符  返回空
     * @param str
     * @param split
     * @return
     */
    protected String getSplitTextSuffix(String str, String split) {
        str = handlerStr(str);
        return str.contains(split) ? str.substring(str.indexOf(split) + split.length()) : "";
    }


    /**
     * 获取分隔符前的文本  不包含分隔符  返回原值
     * @param str
     * @param split
     * @return
     */
    protected String getSplitTextPrefix(String str, String split) {
        str = handlerStr(str);
        String st = str.contains(split) ? str.substring(0,str.indexOf(split) + split.length() - 1) : str;
        String[] split1 = st.split("#");
        StringBuilder sb = new StringBuilder();
        for (int a = 0; a < split1.length; a++) {
            String other = ConvEnum.getFieldName(split1[a]);
            sb.append(other).append(BasicConstant.JIONSTR_1);
        }
        return StrUtil.removeSuffix(sb.toString(),BasicConstant.JIONSTR_1);
    }

    private String handlerStr(String str) {
        if (StrUtil.isEmpty(str)) {
            return "";
        }
        if (str.contains("-")) {
            str = str.replaceAll("-","");
        }
        if (str.contains("#")) {
            String[] strArr = str.split("#");
            Set<String> strings = new HashSet<>(Arrays.asList(strArr));
            List<String> arrList = new ArrayList<>(strings);
            arrList.sort(this::convert);
            String afterProcessing = "";
            for (String s : arrList) {
                afterProcessing += s + "#";
            }
            str = StrUtil.removeSuffix(afterProcessing,"#");
        }
        if ( str.contains(",")) {
            str = str.replaceAll(",","#");
        }
        return str;
    }

    private Integer convert(String o1,String o2){
        Integer integer = 0;  Integer integer2 = 0;
        try {
            integer = Convert.toInt(o1, 9999);
        } catch (Exception e) {
            return 9999;
        }
        try {
            integer2 = Convert.toInt(o2, 9999);
        } catch (Exception e) {
            return -9999;
        }
        return integer - integer2;
    }


    /**
     * 分割  `#`
     * @param str
     * @return
     */
    public String[] splitJ(String str) {
        if (StrUtil.isEmpty(str)) {
            return new String[]{str};
        }
        if ( StrUtil.equals(str,"#undefined") || StrUtil.equals(str,"#无") ) {
            return new String[]{"1"};
        } else if ( str.contains(BasicConstant.JIONSTR_1) ) {
            return str.split("#");
        } else {
            return new String[]{str};
        }
    }


    /**
     * 分割  `,`
     * @param str
     * @return
     */
    public String[] splitD(String str) {
        if (StrUtil.isEmpty(str)) {
            return new String[]{};
        }
        return str.contains(",") ? str.split(",") : new String[]{str};
    }

}
